#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <stdbool.h>
#include <dequeue.h>

#define MAX 40

char *memoria, **fitas, *entrada, word;
int *indices_parado, **indx_inicio_blocos, **count_blocos, qt_blocos=0;
bool flag_passou = false;
bool flag_passou_uma = false;
int qt_fitas;
int i, tam, j, opc;
int current_fita = -1;

float **Alocar_fitas_real (int, int);
void distribui_blocos();
void ordena_memoria(char*, int, int);

int main(void)
{
    //int i, tam, qt_fitas, j, opc;
    do
    {
        system("cls");
        printf("===============================SIMULACAO-INTERCALACAO===============================\n\n");
        printf("1 -> Criar memoria\n");
        printf("2 -> Criar fitas\n");
        printf("3 -> Inserir dados no vetor de entrada\n");
        printf("4 -> Iniciar metodo de intercalacao\n");
        printf("5 -> Imprimir fitas/memoria/vetor de entrada\n");
        printf("10 -> Sair\n\n");
        printf("Opcao: ");
        scanf("%d", &opc);
        switch (opc)
        {
        case 1:
        {
            printf("digite o tamanho da memoria (Maximo de 40): ");
            scanf("%i", &tam);
            if (tam<0)
            {
                printf("O tamanho da memoria deve ser maior que 0");
            }
            else
            {
                memoria = (char*) calloc(tam+1, sizeof( char ) );
            }
            if (memoria == NULL)
            {
                printf("Memoria nao criada!!!");
            }
            else
            {
                printf("memoria criada com sucesso!!!");
            }
            break;
        }
        case 2:
        {
            printf("digite a quantidade de fitas (Maximo de 40 fitas): ");
            scanf("%i", &qt_fitas);
            if (qt_fitas<3)
            {
                printf("A quantidade de fitas deve ser maior que ou igual a 3!!!");
            }
            else
            {
                fitas = Alocar_fitas_real(qt_fitas, 40);
                entrada = (char*) calloc (MAX+1, sizeof ( char ) );
                posiciona_fita(qt_fitas);
                indices_parado[current_fita]=0;
                //entrada = (char*) calloc (1, MAX*sizeof ( char ) );
                if (entrada == NULL)
                {
                    printf("fitas nao criada!!!");
                }
                else
                {
                    printf("fitas criadas com sucesso!!!");
                }
            }
            break;
        }
        case 3:
            {
                i = 0;
                int ind = 0;
                while(!_kbhit())//funcao bkhit le entradas do teclado
                {
                    int h;
                    for(h=0; h<tam;)//loop para distribuicao dos blocos na fita 0
                    {
                        ind = indices_parado[current_fita];
                        fflush(stdin);
                        system("cls");
                        imprime_fitas(qt_fitas);
                        imprime_memoria(tam);
                        imprime_entrada(strlen(entrada)-1);
                        printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");

                        if(memoria[(tam-1)]==NULL)
                        {
                            while(strlen(memoria) < tam)
                            {
                                system("cls");
                                imprime_fitas(qt_fitas);
                                imprime_memoria(tam);
                                imprime_entrada(strlen(entrada)-1);
                                printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");
                                word = tolower(_getch());
                                if(word==13)break;
                                memoria[i] = word;
                                //memoria[i+1] = NULL;
                                i++;
                                system("cls");
                                imprime_fitas(qt_fitas);
                                imprime_memoria(tam);
                                imprime_entrada(strlen(entrada)-1);
                                printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");

                            }
                        }

                        if(word!=13)//{
                            word = tolower(_getch());

                            if (fitas[current_fita][0]==NULL)
                            {
                                indices_parado[current_fita] = 0;
                                ordena_memoria(memoria, tam, h);
                                move_pra_fita(h, false);
                                memoria[h] = word;
                            }
                            else
                            {
                                //if (word != 13)
                                //{
                                    if ((memoria[h]<fitas[current_fita][ind-1])&&(word!=13))
                                    {
                                        if(h<(tam-1))
                                        {
                                            ordena_memoria(memoria, tam, h);
                                            h++;
                                            move_pra_fita(h, false);
                                        }
                                        else
                                        {
                                            h=0;
                                            ordena_memoria(memoria, strlen(memoria)-1, h);
                                            posiciona_fita(qt_fitas);
                                            ind = indices_parado[current_fita];
                                            if(ind != 0){
                                                move_pra_fita(h, true);
                                            }else{
                                                move_pra_fita(h, false);
                                            }
                                        }
                                        if(word!=13)
                                            memoria[h] = word;
                                        else{
                                            word=NULL;
                                            //memoria[h] = word;
                                            //for(int sub_h=h;sub_h<strlen(memoria);sub_h++)
                                             //   memoria[sub_h]=memoria[sub_h+1];
                                        }
                                    }
                                    else
                                    {
                                        if(word!=13){
                                            ordena_memoria(memoria, strlen(memoria)-1, h);
                                            move_pra_fita(h, false);
                                            memoria[h] = word;
                                        }
                                        else{
                                            word=NULL;
                                            char aux;
                                            for(int sub_h=h;sub_h<strlen(memoria);sub_h++)
                                                aux=memoria[sub_h];
                                                memoria[sub_h]=memoria[sub_h+1];
                                                memoria[sub_h+1]=aux;
                                        }
                                    }

                                //}//

                                if(word==NULL)
                                {
                                    if(h>0){
                                        ordena_memoria(memoria, strlen(memoria)-1, h);

                                        for(;h<tam;)
                                        {
                                            if(memoria[h]=='\0')break;

                                            move_pra_fita(h, false);

                                            for(int sub_h=h;sub_h<strlen(memoria);sub_h++)
                                                memoria[sub_h]=memoria[sub_h+1];
                                        }
                                    }

                                    h=0;
                                    posiciona_fita(qt_fitas);
                                    ind = indices_parado[current_fita];
                                    ordena_memoria(memoria, strlen(memoria)-1, h);

                                    bool novoBloco = true;
                                    if(ind != 0){
                                                novoBloco = true;
                                            }else{
                                                novoBloco = false;
                                            }

                                    for(h=0;h<tam; h++)
                                    {
                                        if(memoria[h] != NULL){
                                            move_pra_fita(h, novoBloco);
                                            memoria[h]=NULL;
                                            novoBloco = false;
                                        }
                                    }

                                    fflush(stdin);
                                    system("cls");
                                    imprime_fitas(qt_fitas);
                                    imprime_memoria(tam);
                                    imprime_entrada(strlen(entrada)-1);
                                    printf("\n\nPressione qualquer tecla para voltar ao menu!!!\n");
                                    getch();
                                    break;
                                }
                            }
                       // }
                        //ind++;
                    }
                    break;
                }
                break;
            }
        case 4:
        {
            //metodo de intercalacao
        }
        case 5:
        {
            system("cls");
            imprime_fitas(qt_fitas);
            imprime_memoria(tam);
            imprime_entrada(strlen(memoria)-1);
            printf("\nQualquer tecla para retornar!!!\n");
            getch();
            break;
        }
        }
    }while(opc!=10);
}

float **Alocar_fitas_real (int m, int n)
{
    char **v;  /* ponteiro para a matriz */
    int   i;    /* variavel auxiliar      */

    if (m < 1 || n < 1)   /* verifica parametros recebidos */
    {
        printf ("** Erro: Parametro invalido **\n");
        return (NULL);
    }

    /* aloca as linhas da matriz */
    v =  calloc (m+1, sizeof(char *));	/* Um vetor de m ponteiros para floatv =  calloc (m, sizeof(char *));	/* Um vetor de m ponteiros para float */
    indices_parado =  calloc (m-1, sizeof(int *));	/* Um vetor de m ponteiros para int*/
    //indx_inicio_blocos =  calloc (m-1, sizeof(int *));
    //count_blocos =  calloc (m-1, sizeof(int *));
    if (v == NULL)
    {
        printf ("** Erro: Memoria Insuficiente **");
        return (NULL);
    }

    /* aloca as colunas da matriz */
    for ( i = 0; i < m; i++ )
    {
        v[i] =  calloc (n+1, sizeof(char));	/* m vetores de n floats */
        if (v[i] == NULL)
        {
            printf ("** Erro: Memoria Insuficiente **");
            return (NULL);
        }
    }

    return (v); /* retorna o ponteiro para a matriz */
}

float **Liberar_fitas_real (int m, int n, char **v)
{
    int  i;  /* variavel auxiliar */

    if (v == NULL) return (NULL);
    if (m < 1 || n < 1)    /* verifica parametros recebidos */
    {
        printf ("** Erro: Parametro invalido **\n");
        return (v);
    }
    for (i=0; i<m; i++) free (v[i]); /* libera as linhas da matriz */
    free (v);      /* libera a matriz (vetor de ponteiros) */
    return (NULL); /* retorna um ponteiro nulo */
}

void imprime_fitas (int qt_fitas)
{
    int curFita, curPosicao;
    for (curFita = 0; curFita < qt_fitas; curFita++)
    {
        printf("\n\nFita %d:\n", curFita);
        for ( curPosicao = 0; curPosicao < MAX; curPosicao++)
        {
            if(fitas[curFita][curPosicao]!=NULL ){
                    if(toupper(fitas[curFita][curPosicao]) == fitas[curFita][curPosicao]){
                        printf("   -|-   [ %c ]", tolower(fitas[curFita][curPosicao]));
                    }else
                    {
                        printf("[ %c ]", fitas[curFita][curPosicao]);
                    }
            }
            else
            {
                break;
            }
        }
    }
}

void imprime_memoria (int tam)
{
    int i;
    printf("\n\nMemoria: ");
    for(i = 0; i<tam; i++)
    {
        printf("[ %c ]", memoria[i]);
    }
}

void imprime_entrada (int tam)
{
    int i;
    printf("\nVetor de entrada: ");
    for(i = 0; i<strlen(entrada); i++)
    {
        printf("%c ", entrada[i]);
    }
}

int posiciona_fita(int n_fitas)
{

    if(current_fita < n_fitas-2 && !flag_passou)
    {
            current_fita++;
            return current_fita;
    }
    else
    {
        if(!flag_passou)
        {
            if(!flag_passou_uma){
                flag_passou =true;
                flag_passou_uma = true;
            }
            current_fita =0;
            return current_fita;
        }
        else
        {
            flag_passou =false;
            current_fita =0;
            return current_fita;
        }
    }
}


void ordena_memoria(char *v, int tam, int indice)
{
    int aux, troca, j, i;
    j = tam - 1;
    do
    {
        troca = 0;
        for (i=indice; i<j; i++)
            if (v[i] > v[i+1])
            {
                aux = v[i];
                v[i] = v[i + 1];
                v[i + 1] = aux;
                troca = 1;
            }
        j--;
    }
    while(troca);
}

void imprime_indices()
{
    int i =0;
    for (i=0; i<qt_fitas-1; i++)
    {
        printf("fita:%d **%d \n", i,indices_parado[i]);
    }
    getch();
}
void move_pra_fita(int h, bool novoBloco)
{
    // imprime_indices();
    /*printf("indice %d \n",indices_parado[current_fita]);
    printf("fita %d \n",current_fita);
    printf("h %d \n",h);
    getch();*/
    if(novoBloco)
    {
        fitas[current_fita][indices_parado[current_fita]]=toupper(memoria[h]);
    }
    else
    {
        fitas[current_fita][indices_parado[current_fita]]=memoria[h];
    }
    indices_parado[current_fita]++;
}

int get_next_fita_vazia(int n_fitas)
{
    int fita_vazia = -1;

    for(int i = 0; i < n_fitas; i++)
    {
        if(strlen(fitas[i]) == 0)
        {
            fita_vazia = i;
            break;
        }
    }

    return fita_vazia;
}

void intercalacao_polifasica(){



}
